
var http = require('http')
var https = require('https')
var url = require('url')
var pass = require('stream').PassThrough

var getHeader = function (req) {
  var ret = {}
  for (var i in req.headers) {
    if (!/^(host|connection|Access-|origin|referer|user-agent|user-doclever|path-doclever|url-doclever|method-doclever|headers-doclever|X-Requested-With)/i.test(i)) {
      ret[i] = req.headers[i]
    }
  }
  ret['accept'] = '*/*'
  var headers = req.headers['headers-doclever']
  if (headers) {
    headers = JSON.parse(headers)
    for (var key in headers) {
      ret[key] = headers[key]
    }
  }
  return ret
}

var filterResHeader = function (headers, res) {
  var ret = {}
  res.setHeader('Cache-Control', 'no-cache,no-store')
  res.setHeader('Pragrma', 'no-cache')
  res.setHeader('Expires', 0)
  var resHeaders = res.getHeader('Access-Control-Expose-Headers') ? res.getHeader('Access-Control-Expose-Headers').toLowerCase() : ''
  for (var i in headers) {
    if (!/Access-/i.test(i)) {
      if (/set-cookie/i.test(i)) {
        for (let index = 0; index < headers[i].length; index++) {
          headers[i][index] = headers[i][index].split(' ')[0]
        }
        ret[i] = headers[i]
      } else {
        ret[i] = headers[i]
      }
    }
    if (!resHeaders) {
      res.setHeader('Access-Control-Expose-Headers', i)
    } else if (resHeaders.indexOf(i.toLowerCase() + ',') == -1 && resHeaders.indexOf(',' + i.toLowerCase()) == -1) {
      res.setHeader('Access-Control-Expose-Headers', res.getHeader('Access-Control-Expose-Headers') + ',' + i)
    }
  }
  return ret
}

var getPath = function (req) {
  var url = req.url
  if (url.substr(0, 7).toLowerCase() === 'http://') {
    var i = url.indexOf('/', 7)
    if (i !== -1) {
      url = url.substr(i)
    }
  }
  return url
}

function getHost (req) {
  var url = req.headers['url-doclever']
  url = url.replace(/^(http:\/\/|https:\/\/)/i, '')
  var arr = url.split(':')
  return arr[0]
}

function getPort (req) {
  var url = req.headers['url-doclever']
  var defaultPort
  if (req.headers['url-doclever'].toLowerCase().startsWith('https://')) {
    defaultPort = 443
  } else {
    defaultPort = 80
  }
  url = url.replace(/^(http:\/\/|https:\/\/)/i, '')
  var arr = url.split(':')
  return arr.length > 1 ? arr[1] : defaultPort
}

var onProxy = function (req, res) {
  handleHeader(req, res)
  if (req.method == 'OPTIONS') {
    return
  }
  // console.log("headers="+JSON.stringify(req.headers));
  // console.log("not exist header="+!req.headers["url-doclever"]);
  //console.log(req.headers['url-doclever'])
  if (!req.headers['url-doclever']) {
    mock(req, res)
  } else {
    // console.log("url-doclever:"+req.headers["url-doclever"]);
    proxy(req, res)
  }
}

function mock (req, res) {
  var obj = url.parse(mockUrl)
  var path = req.headers.path || url.parse(req.url).path
  var opt = {
    host: obj.hostname,
    path: (obj.pathname == '/' ? '' : obj.pathname) + path,
    method: req.method,
    headers: getHeader(req),
    port: obj.port ? obj.port : 80
  }
  console.log('初始化请求：method:' + opt.method + ' host:' + opt.host + ' port:' + opt.port + ' path:' + opt.path)
  if (opt.headers['content-length']) {
    delete opt.headers['content-length']
  }
  var req2 = http.request(opt, function (res2) {
    if (!realUrl || res2.headers['finish-doclever'] == '0') {
      console.log('接口正在开发中，返回mock数据')
      res.writeHead(res2.statusCode, filterResHeader(res2.headers, res))
      // res.writeHead(500, filterResHeader(res2.headers,res));
      res2.pipe(res)
      res2.on('end', function () {

      })
    } else {
      if (res2.headers['finish-doclever'] == '1') {
        console.log('接口已完成，调用真实接口')
      } else {
        console.log('接口或数据项没有找到，转调真实接口')
      }
      var headers = getHeader(req)
      var objUrl = url.parse(realUrl)
      var request1, opt1
      if (objUrl.protocol == 'http:') {
        opt1 = {
          host: objUrl.hostname,
          path: (objUrl.pathname == '/' ? '' : objUrl.pathname) + path,
          method: req.method,
          port: objUrl.port ? objUrl.port : 80,
          headers: headers
        }
        request1 = http.request
      } else {
        opt1 = {
          host: objUrl.hostname,
          path: (objUrl.pathname == '/' ? '' : objUrl.pathname) + path,
          method: req.method,
          port: objUrl.port ? objUrl.port : 443,
          headers: headers,
          rejectUnauthorized: false,
          requestCert: true
        }
        request1 = https.request
      }
      console.log('调用真实接口：method:' + opt1.method + ' host:' + opt1.host + ' port:' + opt1.port + ' path:' + opt1.path)
      var req3 = request1(opt1, function (res3) {
        console.log('真实接口调用完成。status:' + res3.statusCode)
        res.writeHead(res3.statusCode, filterResHeader(res3.headers, res))
        res3.pipe(res)
        res3.on('end', function () {

        })
      })
      if (/POST|PUT/i.test(req.method)) {
        stream.pipe(req3)
      } else {
        req3.end()
      }
      req3.on('error', function (err) {
        res.end(err.stack)
      })
    }
  })
  var stream
  if (/POST|PUT|PATCH/i.test(req.method)) {
    stream = new pass()
    req.pipe(stream)
    req.pipe(req2)
  } else {
    req2.end()
  }
  req2.on('error', function (err) {
    res.end(err.stack)
  })
}

function handleHeader (req, res) {
  if (!req.headers.origin) {
    return
  }
  res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With')
  res.setHeader('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE')
  res.setHeader('Access-Control-Allow-Credentials', 'true')
  if (req.headers['access-control-request-headers']) {
    res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers'])
  }
  res.setHeader('Access-Control-Expose-Headers', 'connection,content-length,date,x-powered-by,content-encoding,server,etag,accept-ranges,allow,content-language,set-cookie,doclever-request')
  if (req.method == 'OPTIONS') {
    res.writeHead(200, {'Content-Type': 'text/plain'})
    res.end()
  }
}

function redirect (res, bHttps, opt, location) {
  var urlRedirect = location
  if (urlRedirect.startsWith('/')) {
    urlRedirect = (bHttps ? 'https://' : 'http://') + opt.host + ':' + opt.port + urlRedirect
  }
  var objUrl = url.parse(urlRedirect)
  var request1, opt1
  if (objUrl.protocol == 'http:') {
    opt1 = {
      host: objUrl.hostname,
      path: objUrl.path,
      method: 'GET',
      port: objUrl.port ? objUrl.port : 80
    }
    request1 = http.request
    bHttps = false
  } else {
    opt1 = {
      host: objUrl.hostname,
      path: objUrl.path,
      method: 'GET',
      port: objUrl.port ? objUrl.port : 443,
      rejectUnauthorized: false,
      requestCert: true
    }
    request1 = https.request
    bHttps = true
  }
  var req3 = request1(opt1, function (res3) {
    if (res3.statusCode == 302) {
      redirect(res, bHttps, opt, res3.headers.location)
    } else {
      var resHeader = filterResHeader(res3.headers, res)
      resHeader['doclever-request'] = JSON.stringify(handleSelfCookie(req3))
      res.writeHead(res3.statusCode, resHeader)
      res3.pipe(res)
      res3.on('end', function () {

      })
    }
  })
  req3.end()
  req3.on('error', function (err) {
    res.end(err.stack)
  })
}

function handleSelfCookie (req) {
  var arr = req._headers
  arr['url'] = req.method + ' ' + req.path
  var cookie = arr['cookie']
  if (!cookie) {
    return arr
  }
  var arrCookie = cookie.split(';')
  var keys = ['id', 'name', 'photo', 'qq', 'sex', 'company', 'phone', 'loginCount', 'age', 'email']
  arrCookie = arrCookie.filter(function (obj) {
    obj = obj.trim()
    for (let key of keys) {
      if (obj.startsWith(key + '=')) {
        return false
      }
    }
    return true
  })
  arr['cookie'] = arrCookie.join(';')
  return arr
}

function proxy (req, res) {
  var bHttps = false
  if (req.headers['url-doclever'].toLowerCase().startsWith('https://')) {
    bHttps = true
  }
  var opt, request
  if (bHttps) {
    opt = {
      host: getHost(req),
      path: req.headers['path-doclever'],
      method: req.headers['method-doclever'],
      headers: getHeader(req),
      port: getPort(req),
      rejectUnauthorized: false,
      requestCert: true
    }
    request = https.request
  } else {
    opt = {
      host: getHost(req),
      path: req.headers['path-doclever'],
      method: req.headers['method-doclever'],
      headers: getHeader(req),
      port: getPort(req)
    }
    request = http.request
  }
  var req2 = request(opt, function (res2) {
    if (res2.statusCode == 302) {
      redirect(res, bHttps, opt, res2.headers.location)
    } else {
      var resHeader = filterResHeader(res2.headers, res)
      resHeader['doclever-request'] = JSON.stringify(handleSelfCookie(req2))
      res.writeHead(res2.statusCode, resHeader)
      res2.pipe(res)
      res2.on('end', function () {

      })
    }
  })
  if (/POST|PUT|PATCH/i.test(req.method)) {
    req.pipe(req2)
  } else {
    req2.end()
  }
  req2.on('error', function (err) {
    res.end(err.stack)
  })
}

var faceConfig = require('./faceConfig.js')
var args = [faceConfig.mockServer, faceConfig.devServer]
var mockUrl = args[0]
var realUrl = args[1]
var port = args[2] ? args[2] : 36742
var server = http.createServer(onProxy)
server.listen(port)
console.log(args.length > 0 ? ('内网测试，Mock数据正监听端口：' + port) : '正在运行，请用DOClever的接口测试页面进行内网测试！')
